using ServiceStack.Redis;
using System;
using System.Collections.Generic;
using System.Configuration;
using ServiceStack.Redis.Generic;
using Newtonsoft.Json;

namespace Cache.Redis
{
    public class RedisConnect : ICacheHelper
    {
        /// 配置文件中ip地址端口号
        /// <summary>
        /// 配置文件中ip地址端口号
        /// </summary>
        private static string redisAppsettingsKey = "";

        private static int Db = 0;

        private static string redisvalue = "";

        /// 读数据Redis服务IP地址端口号
        /// <summary>
        /// 读数据Redis服务IP地址端口号
        /// </summary>
        private static string[] _ReadClientHosts;

        /// 写数据Redis服务IP地址端口号
        /// <summary>
        /// 写数据Redis服务IP地址端口号
        /// </summary>
        private static string[] _WriteClientHosts;

        /// RedisClient链接池管理
        /// <summary>
        /// RedisClient链接池管理
        /// </summary>
        private static PooledRedisClientManager _RedisClientManager;

        /// 读数据Redis服务IP地址端口号
        /// <summary>
        /// 读数据Redis服务IP地址端口号
        /// </summary>
        private static string[] ReadClientHosts
        {
            get
            {
                if (null == RedisConnect._ReadClientHosts)
                {
                    string text;
                    if (string.IsNullOrEmpty(RedisConnect.redisAppsettingsKey))
                    {
                        text = (string.IsNullOrEmpty(RedisConnect.redisvalue) ? ConfigurationManager.AppSettings["RedisReadServer"] : RedisConnect.redisvalue);
                    }
                    else
                    {
                        text = ConfigurationManager.AppSettings[RedisConnect.redisAppsettingsKey];
                    }
                    RedisConnect._ReadClientHosts = text.Split(new char[]
					{
						','
					});
                }
                return RedisConnect._ReadClientHosts;
            }
        }

        /// 写数据Redis服务IP地址端口号
        /// <summary>
        /// 写数据Redis服务IP地址端口号
        /// </summary>
        private static string[] WriteClientHosts
        {
            get
            {
                if (null == RedisConnect._WriteClientHosts)
                {
                    string text;
                    if (string.IsNullOrEmpty(RedisConnect.redisAppsettingsKey))
                    {
                        text = (string.IsNullOrEmpty(RedisConnect.redisvalue) ? ConfigurationManager.AppSettings["RedisWriteServer"] : RedisConnect.redisvalue);
                    }
                    else
                    {
                        text = ConfigurationManager.AppSettings[RedisConnect.redisAppsettingsKey];
                    }
                    RedisConnect._WriteClientHosts = text.Split(new char[]
					{
						','
					});
                }
                return RedisConnect._WriteClientHosts;
            }
        }

        /// RedisClient链接池管理
        /// <summary>
        /// RedisClient链接池管理
        /// </summary>
        private PooledRedisClientManager RedisClientManager
        {
            get
            {
                if (null == RedisConnect._RedisClientManager)
                {
                    RedisConnect._RedisClientManager = this.CreateManager(RedisConnect.WriteClientHosts, RedisConnect.ReadClientHosts);
                }
                return RedisConnect._RedisClientManager;
            }
        }

        /// 读取web.config中redis连接配置
        /// <summary>
        /// 读取web.config中redis连接配置
        /// </summary>
        /// <param name="key">配置文件中ip地址端口号 key值</param>
        /// <param name="db">数据库</param>
        public RedisConnect(string key, int db = 0)
        {
            RedisConnect.redisAppsettingsKey = key;
            RedisConnect.Db = db;

            RedisConnect._RedisClientManager = null; //清除redis连接配置
        }

        ///// 直接传入redis连接字符串
        ///// <summary>
        ///// 直接传入redis连接字符串
        ///// </summary>
        ///// <param name="key"></param>
        ///// <param name="value">传入的 密码@ip:port 值</param>
        ///// <param name="db">数据库</param>
        //public RedisHelper(string value, int db = 0)
        //{
        //    RedisHelper.redisAppsettingsKey = "";
        //    RedisHelper.redisvalue = value;
        //    RedisHelper.Db = db;

        //    RedisHelper._RedisClientManager = null; //清除redis连接配置
        //}

        public RedisConnect()
        {
        }

        /// 创建缓存客户端链接池管理
        /// <summary>
        /// 创建缓存客户端链接池管理
        /// </summary>
        /// <param name="readWriteHosts">读写服务器Host</param>
        /// <param name="readOnlyHosts">只读数据库Host</param>
        /// <returns></returns>
        private PooledRedisClientManager CreateManager(string[] readWriteHosts, string[] readOnlyHosts)
        {
            return new PooledRedisClientManager(readWriteHosts, readOnlyHosts, new RedisClientManagerConfig
            {
                MaxWritePoolSize = 5000,
                MaxReadPoolSize = 5000,
                AutoStart = true
            }, RedisConnect.Db, 10, null);
        }

        /// 得到用于读取的客户端对象
        /// <summary>
        /// 得到用于读取的客户端对象
        /// </summary>
        /// <returns>只读客户端对象</returns>
        public IRedisClient GetReadClient()
        {
            return this.RedisClientManager.GetReadOnlyClient();
        }

        /// 得到用于写入的客户端对象
        /// <summary>
        /// 得到用于写入的客户端对象
        /// </summary>
        /// <returns></returns>
        public IRedisClient GetWriteClient()
        {
            return this.RedisClientManager.GetClient();
        }


        /// 是否存在key
        /// <summary>
        /// 是否存在key
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool Exists(string key)
        {
            bool result;
            using (IRedisClient readClient = this.GetReadClient())
            {
                result = readClient.ContainsKey(key);
            }
            return result;
        }

        public T Get<T>(string key)
        {
            T result;
            using (IRedisClient readClient = this.GetReadClient())
            {
                result = readClient.Get<T>(key);
            }
            return result;
        }

        public object Get(string key)
        {
            object result;
            using (IRedisClient readClient = this.GetReadClient())
            {
                result = readClient.Get<object>(key);
            }
            return result;
        }

        public List<string> GetAllKey()
        {
            System.Collections.Generic.List<string> allKeys;
            using (IRedisClient readClient = this.GetReadClient())
            {
                allKeys = readClient.GetAllKeys();
            }
            return allKeys;
        }

        public List<string> GetAllKey(string cacheKeyPrefix)
        {
            System.Collections.Generic.List<string> result;
            using (IRedisClient readClient = this.GetReadClient())
            {
                result = readClient.SearchKeys("*" + cacheKeyPrefix + "*");
            }
            return result;
        }

        public List<T> GetAll<T>(string cacheKeyPrefix)
        {
            System.Collections.Generic.List<T> values;
            using (IRedisClient readClient = this.GetReadClient())
            {
                System.Collections.Generic.List<string> keys = readClient.SearchKeys("*" + cacheKeyPrefix + "*");
                values = readClient.GetValues<T>(keys);
            }
            return values;
        }

        public List<T> GetAll<T>(System.Collections.Generic.List<string> keys)
        {
            System.Collections.Generic.List<T> values;
            using (IRedisClient readClient = this.GetReadClient())
            {
                values = readClient.GetValues<T>(keys);
            }
            return values;
        }

        public bool Set<T>(string key, T value)
        {
            bool result;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                result = writeClient.Set<T>(key, value);
            }
            return result;
        }

        public bool Set<T>(string key, T value, int minutes)
        {
            bool result;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                result = writeClient.Set<T>(key, value, System.DateTime.Now.AddMinutes((double)minutes));
            }
            return result;
        }

        public bool Set<T>(string key, T value, System.TimeSpan ts)
        {
            bool result;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                result = writeClient.Set<T>(key, value, ts);
            }
            return result;
        }

        public bool Add<T>(string key, T value)
        {
            bool result;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                result = writeClient.Add<T>(key, value);
            }
            return result;
        }

        public bool Add<T>(string key, T value, System.TimeSpan expireTime)
        {
            bool result;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                result = writeClient.Add<T>(key, value, expireTime);
            }
            return result;
        }

        /// 设置过期时间
        /// <summary>
        /// 设置过期时间
        /// </summary>
        /// <param name="key"></param>
        /// <param name="expireAt"></param>
        /// <returns></returns>
        public bool ExpireEntry(string key, DateTime expireAt)
        {
            bool result;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                result = writeClient.ExpireEntryAt(key, expireAt);
            }
            return result;
        }

        /// 设置过期时间
        /// <summary>
        /// 设置过期时间
        /// </summary>
        /// <param name="key"></param>
        /// <param name="expireIn"></param>
        /// <returns></returns>
        public bool ExpireEntry(string key, TimeSpan expireIn)
        {
            bool result;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                result = writeClient.ExpireEntryIn(key, expireIn);
            }
            return result;
        }

        #region set

        public bool AddItemToSortedSet(string setId, string value)
        {
            bool result;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                result = writeClient.AddItemToSortedSet(setId, value);
            }
            return result;
        }

        #endregion set

        #region hash

        public void SetRangeInHash(string hashkey, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, string>> values)
        {
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                writeClient.SetRangeInHash(hashkey, values);
            }
        }

        public bool SetEntryInHashIfNotExists(string hashId, string key, string value)
        {
            bool result;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                result = writeClient.SetEntryInHashIfNotExists(hashId, key, value);
            }
            return result;
        }

        public bool SetEntryInHash(string hashId, string key, string value)
        {
            bool result;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                result = writeClient.SetEntryInHash(hashId, key, value);
            }
            return result;
        }

        public bool SetEntryInHash<T>(string hashId, string key, T value, int minutes)
        {
            throw new System.NotImplementedException();
        }

        public bool SetEntryInHash<T>(string hashId, string key, T value)
        {
            throw new System.NotImplementedException();
        }

        public T GetHash<T>(string hashId, string key)
        {
            throw new System.NotImplementedException();
        }

        public string GetHash(string hashId, string key)
        {
            string valueFromHash;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                valueFromHash = writeClient.GetValueFromHash(hashId, key);
            }
            return valueFromHash;
        }

        public int GetHashLength(string hashId)
        {
            int hashCount;
            using (IRedisClient readClient = this.GetReadClient())
            {
                hashCount = readClient.GetHashCount(hashId);
            }
            return hashCount;
        }

        public System.Collections.Generic.Dictionary<string, string> GetAllEntriesFromHash(string hashId)
        {
            System.Collections.Generic.Dictionary<string, string> allEntriesFromHash;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                allEntriesFromHash = writeClient.GetAllEntriesFromHash(hashId);
            }
            return allEntriesFromHash;
        }

        public string GetEntriesFromHash(string hashId, string key)
        {
            string valueFromHash;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                valueFromHash = writeClient.GetValueFromHash(hashId, key);
            }
            return valueFromHash;
        }

        public List<string> GetValuesFromHash(string hashId, string[] keys)
        {
            System.Collections.Generic.List<string> values;
            using (IRedisClient readClient = this.GetReadClient())
            {
                values = readClient.GetValuesFromHash(hashId, keys);
            }
            return values;
        }

        public bool RemoveEntryFromHash(string hashId, string key)
        {
            bool result;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                result = writeClient.RemoveEntryFromHash(hashId, key);
            }
            return result;
        }

        #endregion hash

        #region list

        public void AddItemToList(string listId, string value)
        {
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                writeClient.AddItemToList(listId, value);
            }
        }

        public void AddRangeToList(string listId, System.Collections.Generic.List<string> values)
        {
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                writeClient.AddRangeToList(listId, values);
            }
        }

        public int GetListCount(string listId)
        {
            int listCount;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                listCount = writeClient.GetListCount(listId);
            }
            return listCount;
        }

        public List<string> GetAllItemsFromList(string listId)
        {
            System.Collections.Generic.List<string> allItemsFromList;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                allItemsFromList = writeClient.GetAllItemsFromList(listId);
            }
            return allItemsFromList;
        }

        /// <summary>
        /// 移除list中，key/value,与参数相同的值，并返回移除的数量
        /// </summary>  
        public long RemoveItemFromList(string key, string value)
        {
            long result = 0;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                result = writeClient.RemoveItemFromList(key, value);
            }
            return result;
        }

        #endregion list

        #region 队列queue

        public void EnqueueItem(string key, string val)
        {
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                writeClient.EnqueueItemOnList(key, val);
            }
        }

        public string DequeueItem(string key)
        {
            string result;
            using (IRedisClient readClient = this.GetReadClient())
            {
                result = readClient.DequeueItemFromList(key);
            }
            return result;
        }

        #endregion 队列queue

        #region 自增increment value必须为integer

        public long Increment(string key, int addVal)
        {
            long result;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                result = writeClient.IncrementValueBy(key, addVal);
            }
            return result;
        }

        public int Increment(string hashId, string key, int incrementBy)
        {
            int result;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                result = writeClient.IncrementValueInHash(hashId, key, incrementBy);
            }
            return result;
        }

        #endregion 自增increment value必须为integer

        #region 删除数据

        /// 删除数据
        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool Remove(string key)
        {
            bool result;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                result = writeClient.Remove(key);
            }
            return result;
        }

        public void RemoveAll(string cacheKeyPrefix)
        {
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                System.Collections.Generic.List<string> list = writeClient.SearchKeys("*" + cacheKeyPrefix + "*");
                foreach (string current in list)
                {
                    writeClient.Remove(current);
                }
            }
        }

        public void RemoveAll(List<string> keys)
        {
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                foreach (string current in keys)
                {
                    writeClient.Remove(current);
                }
            }
        }

        /// 清空整个redis服务器的数据
        /// <summary>
        /// 清空整个redis服务器的数据
        /// </summary>
        public void FlushAll()
        {
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                writeClient.FlushAll();
            }
        }

        /// 删除当前数据库中所有数据
        /// <summary>
        /// 删除当前数据库中所有数据
        /// </summary>
        public void FlushDb()
        {
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                writeClient.FlushDb();
            }
        }

        #endregion 删除数据

        #region 持久化数据

        public void Save()
        {
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                writeClient.Save();
            }
        }

        #endregion 持久化数据

        #region redis封装

        /// hash 是否存在该key值
        /// <summary>
        /// hash 是否存在该key值
        /// </summary>
        /// <param name="hashId"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool IsHashContainsEntry(string hashId, string key)
        {
            bool result;
            using (IRedisClient writeClient = this.GetWriteClient())
            {
                result = writeClient.HashContainsEntry(hashId, key);
            }
            return result;
        }


        /// <summary>
        /// 保存单个hash值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public bool SaveHashObjectData<T>(T t) where T : Model.Public.BaseEntity, new()
        {
            return SaveHashObjectData<T>(t.GetKey(), t);
        }

        public bool SaveHashObjectData<T>(string key, T t) where T : Model.Public.BaseEntity, new()
        {
            string hashId = t.GetDBName();
            string value = MiniJSON.Json.Serialize(t.ModelChangeToDic());
            bool result = SetEntryInHash(hashId, key, value);
            return result;
        }

        /// 获取单个hash对象
        /// <summary>
        /// 获取单个hash对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public T GetObjectDataByKey<T>(string key) where T : Model.Public.BaseEntity, new()
        {
            T t = new T();
            string json_txt = GetHash(t.GetDBName(), key);
            Dictionary<string, object> json_obj = MiniJSON.Json.Deserialize(json_txt) as Dictionary<string, object>;
            t.DicChangeToModel(json_obj);
            return t;
        }

        /// 获取list
        /// <summary>
        /// 获取list
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="listId"></param>
        /// <returns></returns>
        public List<T> GetAllListByListId<T>(string listId) where T : Model.Public.BaseEntity, new()
        {
            List<T> list = new List<T>();
            List<string> list_str = GetAllItemsFromList(listId);
            foreach (var item in list_str)
            {
                T t = new T();
                Dictionary<string, object> json_obj = MiniJSON.Json.Deserialize(item) as Dictionary<string, object>;
                t.DicChangeToModel(json_obj);

                list.Add(t);
            }
            return list;
        }

        #endregion redis封装

    }
}
